package com.jing.cloud.service.method;

import com.google.common.base.Preconditions;
import com.jing.cloud.util.ErrCode;
import com.jing.cloud.service.Res;
import com.jing.cloud.util.RspUtil;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Set;

public abstract class AbstractMethod<T> implements Method<T> {

    private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();


    private static ThreadLocal<Long> TLuserId = new ThreadLocal<>();

    @Override
    public void setUserId(long userId) {
        this.TLuserId.set(userId);
    }

    @Override
    public long getUserId() {
        Long userId = TLuserId.get();
        Preconditions.checkNotNull(userId, "user id is null");
        Preconditions.checkArgument(userId != 0, "user id is 0");
        return userId;
    }

    /**
     * 子类调用时获取父类中的泛型
     * 江南白衣
     */
    @SuppressWarnings("unchecked")
    @Override
    public Class<T> getClazz() {
        Class<T> clazz = null;
        Type t = getClass().getGenericSuperclass();
        if (t instanceof ParameterizedType) {
            Type[] p = ((ParameterizedType) t).getActualTypeArguments();
            clazz = (Class<T>) p[0];
        }

        return clazz;
    }

    @Override
    public Res valid(T t) throws Exception {
        Res res;
        Set<ConstraintViolation<T>> cvs = validator.validate(t);
        StringBuilder sb = new StringBuilder();
        for (ConstraintViolation<T> cv : cvs) {
            sb.append(cv.getPropertyPath().toString());
            sb.append(" ");
            sb.append(cv.getMessage());
            sb.append("\t");
        }
        if (cvs.isEmpty()) {
            res = RspUtil.success();
        } else {
            res = RspUtil.error(ErrCode.PARAM_INVALID, sb.toString());
        }
        return res;
    }

    public Res validAndRun(T t) throws Exception {
        Res res = valid(t);
        if (res.getCode() == ErrCode.SUCCESS) {
            res = call(t);
        }
        return res;
    }

}
